
(function($){

    var XqTools = function(){

        var self = this;

        var $obj = null;

        var childrenList = [];

        var config = {
            width:false,
            height:false,
            vertical:false,
            horizontal:false,
            page:false,
            center:false,
            duration: 300,
            inertia: 200,
            animate:false,
            clickIndex:false,
            move:true,
            selected:function(index){},
            init:function(){},
            before:function(){}
        };

        var data = {
            width:0,
            height:0,
            currentIndex:0,
            length:0,
            start:0,
            end:0,
            relStart:0,
            relEnd:0,
            lastLocation:0,
            direction:'vertical',
            init:false,
            webkit:false,
            isAnimate:false
        };

        this.init = function(option,obj){

            $obj = obj;

            config = $.extend(config,option);

            config.before();

            if(config.vertical || config.horizontal){
                data.direction = config.vertical ? 'vertical' : 'horizontal';
            }

            if(config.animate == 'js'){
                data.webkit = false;
            }else if(config.animate == 'html5'){
                data.webkit = true;
            }else{
                data.webkit = self.methods.isWebkit();
            }

            $obj.children().each(function(index){
                var childrenSelf = $(this);
                childrenSelf.css({
                    'float':'left'
                });
                childrenSelf.addClass('XqTools_'+index);
                data.length = index;
                childrenList.push({
                    size:data.direction == 'vertical' ? childrenSelf[0].offsetHeight : childrenSelf[0].offsetWidth,
                    distance:data.length ? childrenList[data.length-1]['size'] + childrenList[data.length-1]['distance'] : 0
                });
                if(config.clickIndex){
                    childrenSelf.on('click',function(){
                        if(self.menuEvent.data.isStart){
                            self.setIndex($(this).index())
                        }
                    });
                }
            });
            data.width = config.width ? config.width : 'auto';
            data.height = config.height ? config.height : 'auto';

            var parent = $('<div class="XqTools_parent"></div>');
            parent.css({
                'width':data.width,
                'height':data.height,
                'padding':0,
                'margin':0,
                'display':'block',
                'overflow':'hidden',
                'position':'relative'
            });
            $obj.wrap(parent);

            $obj.css({
                'display':'block',
                'overflow':'hidden',
                'position':'absolute',
                'top':0,
                'left':0,
                'margin':0,
                'padding':0
            });

            if(config.center) data.start = data.direction == 'vertical' ? data.height/2 : data.width/2;
            data.end = data.start - childrenList[data.length]['distance'] - childrenList[data.length]['size'];
            if(!config.center) data.end = data.end + (data.direction == 'vertical' ? data.height : data.width);
            data.relStart = config.center ? data.start - childrenList[0]['size']/2 : data.start;
            data.relEnd = config.center ? data.end + childrenList[data.length]['size']/2 : data.end;

            $obj.css({
                'width':data.direction == 'vertical' ? data.width : childrenList[data.length]['distance']+childrenList[data.length]['size'],
                'height':data.direction == 'horizontal' ? data.height : childrenList[data.length]['distance']+childrenList[data.length]['size']
            });
            data.currentIndex = 0;
            config.selected(data.currentIndex);
            self.methods.setLocation(self.methods.getIndexLocation(0));

            if(data.webkit){
                $obj.css({
                    '-webkit-transition-property': '-webkit-transform',
                    '-webkit-transition-duration': config.duration + 'ms',
                    '-webkit-transition-timing-function': 'ease-out'
                });
            }

            if(config.move){
                $obj.bind('mousedown',function(event){
                    if(data.isAnimate) return;
                    self.menuEvent.init();
                    self.menuEvent.down(event);
                    $(document).bind('mousemove.XqTools',function(event){
                        self.menuEvent.move(event);
                    });
                    $(document).bind('mouseup.XqTools',function(event){
                        self.menuEvent.up(event);
                        $(document).unbind('.XqTools');
                    });
                });

                try{
                    var touchmove  = function(event){
                        self.menuEvent.touchMove(event);
                    };
                    var touchend = function(event){
                        self.menuEvent.touchEnd(event);
                        document.removeEventListener('touchmove',touchmove,true);
                        document.removeEventListener('touchend',touchend,true);
                        document.removeEventListener('touchcancel',touchend,true);
                    };
                    $obj[0].addEventListener('touchstart',function(event){
                        if(data.isAnimate) return;
                        self.menuEvent.init();
                        self.menuEvent.touchStart(event);
                        document.addEventListener('touchmove',touchmove,true);
                        document.addEventListener('touchend',touchend,true);
                        document.addEventListener('touchcancel', touchend, true);
                    });
                }catch (E){
                    console.log(E.message);
                }
            }
            config.init();
            data.init = true;
            return {resize:self.resize,setIndex:self.setIndex};
        }

        this.resize = function(width,height){
            console.log(width,height);
            config.before();
            childrenList = [];
            $obj.children().each(function(index){
                var childrenSelf = $(this);
                data.length = index;
                childrenList.push({
                    size:data.direction == 'vertical' ? childrenSelf.height() : childrenSelf.width(),
                    distance:data.length ? childrenList[data.length-1]['size'] + childrenList[data.length-1]['distance'] : 0
                });
            });

            data.width = width ? width : data.width;
            data.height = height ? height : data.height;
            $('.XqTools_parent').css({
                'width':data.width,
                'height':data.height
            });

            if(config.center) data.start = data.direction == 'vertical' ? data.height/2 : data.width/2;
            data.end = data.start - childrenList[data.length]['distance'] - childrenList[data.length]['size'];
            if(!config.center) data.end = data.end - (data.direction == 'vertical' ? data.height : data.width);
            data.relStart = config.center ? data.start - childrenList[0]['size']/2 : data.start;
            data.relEnd = config.center ? data.end + childrenList[data.length]['size']/2 : data.end;

            $obj.css({
                'width':data.direction == 'vertical' ? data.width : childrenList[data.length]['distance']+childrenList[data.length]['size'],
                'height':data.direction == 'horizontal' ? data.height : childrenList[data.length]['distance']
            });
            self.methods.setLocation(self.methods.getIndexLocation(data.currentIndex));

        }

        this.setIndex = function(index){
            self.methods.setLocationAnimate(self.methods.getIndexLocation(index));
        }

        this.methods = {
            isWebkit:function() {
                var Sys={};
                var na = navigator.userAgent.toLowerCase();
                Sys.ie = window.ActiveXObject ? true : false;
                Sys.firefox = document.getBoxObjectFor ? true : false;
                Sys.chrome = (window.MessageEvent&&!document.getBoxObjectFor) ? true : false;
                Sys.opera = window.opera ? true : false;
                Sys.safari = window.openDatabase? true : false;
                return document.body.style.WebkitBoxShadow !== undefined && !Sys.safari;
            },
            getIndexLocation:function(index){
                return data.start-childrenList[index]['distance']-(config.center ? childrenList[index]['size']/2 : 0);
            },
            isLeftInIndex:function(index,location){
                var distance = childrenList[index]['distance'];
                var size = childrenList[index]['size'];
                var leftCenter = index+1 <= data.length ? childrenList[index+1]['size']/2 : 0;
                return location > data.relStart - distance - leftCenter + (data.page ? leftCenter : 0);
            },
            isRightInIndex:function(index,location){
                var distance = childrenList[index]['distance'];
                var size = childrenList[index]['size'];
                var rightCenter = index-1 >= 0 ? childrenList[index-1]['size']/2 : 0;
                return location <= data.relStart - distance + rightCenter + (data.page ? rightCenter : 0);
            },
            setLocation:function(location){
                self.methods.setCurrent(self.methods.getCurrent(location));
                var x = data.direction == 'horizontal' ? location : 0;
                var y = data.direction == 'vertical' ? location : 0;
                if(data.webkit){
                    $obj.css({'-webkit-transition-property': 'null'});
                    $obj.css({'-webkit-transform': 'translate3d('+x+'px, '+y+'px, 0px)'});
                }else{
                    $obj.css({'top':y,'left':x});
                }
                data.lastLocation = location;
            },
            setLocationAnimate:function(location,easing){
                data.isAnimate = true;
                if (easing == 'undefined') easing = 'swing';
                if (config.page){
                    location = self.methods.getIndexLocation(self.methods.getCurrent(location));
                }
                var x = data.direction == 'horizontal' ? location : 0;
                var y = data.direction == 'vertical' ? location : 0;
                if(data.webkit){
                    $obj.css({'-webkit-transition-property': '-webkit-transform'});
                    $obj.css({'-webkit-transform': 'translate3d('+x+'px, '+y+'px, 0px)'});
                }else{
                    $obj.animate({'top':y,'left':x}, config.duration, easing);
                }
                var interval = setInterval(function() {
                    var location = data.direction == 'vertical' ? $obj.position().top : $obj.position().left;
                    self.methods.setCurrent(self.methods.getCurrent(location));
                    data.lastLocation = location;
                }, 20);
                setTimeout(function(){
                    clearInterval(interval);
                    $obj.css({'-webkit-transition-property': 'null'});
                    data.isAnimate = false;
                },config.duration+100);
            },
            setCurrent:function(index){
                if (data.currentIndex != index || !data.init) {
                    $obj.children('.XqTools_'+data.currentIndex).removeClass('active');
                    $obj.children('.XqTools_'+index).addClass('active');
                }
                data.currentIndex = index;
                config.selected(index);
            },
            getCurrent:function(location){
                if (location == data.lastLocation) return data.currentIndex;
                var index = 0;
                var select = false;
                var currentIndex = 0;
                if (location < data.lastLocation) {
                    for(var i = data.currentIndex;i<=data.length;i++){
                        if (self.methods.isLeftInIndex(i,location)) {
                            index = i;
                            select = true;
                            break;
                        }
                    }
                    currentIndex = select ? index : data.length;
                } else {
                    for(var i = data.currentIndex;i>=0;i--){
                        if (self.methods.isRightInIndex(i,location)) {
                            index = i;
                            select = true;
                            break;
                        }
                    }
                    currentIndex = select ? index : 0;
                }
                return currentIndex;
            }
        }

        this.menuEvent = {
            data : {startX:0,startY:0,startD:0,moveX:0,moveY:0,type:0,isMove:true,isStart:true},
            eventList : [],
            init : function(){
                self.menuEvent.data = {startX:0,startY:0,startD:0,moveX:0,moveY:0,type:0,isMove:true,isStart:true};
                self.menuEvent.data.startD = Math.round(data.direction == 'vertical' ? $obj.position().top : $obj.position().left);
                self.menuEvent.eventList = [];
            },
            down:function(event){
                self.menuEvent.data.startX = Math.round(event.pageX);
                self.menuEvent.data.startY = Math.round(event.pageY);
                self.menuEvent.stop(event);
            },
            move:function(event){
                var location = self.menuEvent.moveAndUp(event);
                self.menuEvent.data.isStart = false;
                self.methods.setLocation(location);
                self.menuEvent.stop(event);
            },
            up:function(event){
                if(self.menuEvent.data.isStart) return;
                var distance = self.menuEvent.moveAndUp(event)
                distance = self.menuEvent.getDistance(distance);
                self.methods.setLocationAnimate(distance,'inertia');
                self.menuEvent.stop(event);
            },
            moveAndUp:function(event){
                var date = new Date();
                self.menuEvent.data.moveX = self.menuEvent.data.startX - Math.round(event.pageX) ;
                self.menuEvent.data.moveY = self.menuEvent.data.startY - Math.round(event.pageY) ;
                var distance = data.direction == 'vertical' ? self.menuEvent.data.moveY : self.menuEvent.data.moveX;
                distance = distance*-1 + self.menuEvent.data.startD;
                if(self.menuEvent.eventList.length != 'undefined' && self.menuEvent.eventList.length > 0 ){
                    var type = (distance - self.menuEvent.eventList[self.menuEvent.eventList.length-1]['distance']) > 0 ? 1 : 2 ;
                    if(self.menuEvent.data.type != 0 && type != self.menuEvent.data.type){
                        self.menuEvent.eventList = [];
                    }
                    self.menuEvent.data.type = type;
                }
                self.menuEvent.eventList.push({time:date.getTime(),location:distance});
                if (self.menuEvent.eventList.length > 6) {
                    self.menuEvent.eventList.shift();
                };
                return distance;
            },
            stop:function(event){
                event.stopPropagation();
                event.preventDefault();
            },
            touchStart:function(event){
                self.menuEvent.data.startX = Math.round(event.touches[0].pageX);
                self.menuEvent.data.startY = Math.round(event.touches[0].pageY);
            },
            touchMove:function(event){
                var distance;
                if(self.menuEvent.data.isMove){
                    var eventM = {};
                    eventM.pageX = event.touches[0].pageX;
                    eventM.pageY = event.touches[0].pageY;
                    distance = self.menuEvent.moveAndUp(eventM);
                }
                if(self.menuEvent.data.isStart){
                    var x = Math.abs(self.menuEvent.data.moveX);
                    var y = Math.abs(self.menuEvent.data.moveY);
                    self.menuEvent.data.isMove = data.direction == 'vertical' ? y > x : x > y;
                    self.menuEvent.data.isStart = false;
                }
                if(self.menuEvent.data.isMove){
                    self.methods.setLocation(distance);
                    self.menuEvent.stop(event);
                }
            },
            touchEnd:function(event){
                if(self.menuEvent.data.isStart) return;
                var distance = data.direction == 'vertical' ? self.menuEvent.data.moveY : self.menuEvent.data.moveX;
                distance = distance*-1 + self.menuEvent.data.startD;
                distance = self.menuEvent.getDistance(distance);
                self.methods.setLocationAnimate(distance,'inertia');
                self.menuEvent.stop(event);
            },
            getDistance:function(distance){
                var time = self.menuEvent.eventList[self.menuEvent.eventList.length-1].time - self.menuEvent.eventList[0].time;
                var range = self.menuEvent.eventList[self.menuEvent.eventList.length-1].location - self.menuEvent.eventList[0].location;
                var autoDistance = range / time * config.inertia;
                distance = distance + autoDistance;
                if (distance >= data.relStart) {
                    distance = data.relStart;
                }else if(distance <= data.relEnd){
                    distance = data.relEnd;
                }
                return distance;
            }
        }
    }

    $.fn.XqTools = function(option){
        var tools = new XqTools();
        return tools.init(option,$(this));
    }

})(jQuery);
jQuery.extend(jQuery.easing, {
    inertia: function (x, t, b, c, d) {
        return c*((t=t/d-1)*t*t + 1) + b;
    }
});